namespace classifier_test
{

class repro_classifier : public stream_classifier
{
public:
	repro_classifier();
	repro_classifier(const repro_classifier& Val);
	smart_ptr<stream_classifier> clone() const;
	int get_window_size() const;
	void set_window_size(int Val);
	int get_stable_learning_size() const;
	void set_stable_learning_size(int Val);
	double get_trigger_error_threshold() const;
	void set_trigger_error_threshold(double Val);
	double get_probability_threshold() const;
	void set_probability_threshold(double Val);
	double get_accuracy_threshold() const;
	void set_accuracy_threshold(double Val);
	double get_equivalence_threshold() const;
	void set_equivalence_threshold(double Val);

	void build(subarray<const stream_record* const> Data);
	void train(const stream_record& LabeledRecord);
	void estimate(const stream_record& Record, array<double>& Probs) const;
	int get_concept_count() const;

protected:
	void initialize_options(command_line_options& Options) const;
	void apply_arguments(const command_line_arguments& Args);

private:
	struct concept
	{
		smart_ptr<classifier> Classifier;
		map<concept*, int> ShiftCounts;
		int ShiftCount;
	};
	typedef map<concept*, smart_ptr<concept> > concept_map;

	int WinSize;
	int StLearnSize;
	double TrigErrTh;
	double ProbTh;
	double AccuTh;
	double EquTh;

	vector<smart_ptr<stream_record> > TrData;
	vector<char> TrHits;
	vector<int> TmpTrigs;
	vector<smart_ptr<classifier> > TmpClassifiers;
	int WinBegin;
	classifier* CurrClassifier;
	concept* LastConcept;
	concept_map Concepts;

	bool detect_trigger();
	void add_tmp_trigger(int Pos);
	void add_stable_trigger(int Pos);
	void add_concept(smart_ptr<classifier> Classifier);
	concept* find_equivalent_concept(classifier* Classifier);
	classifier* find_next_classifier();
	double accuracy_rate(classifier* Classifier, int Begin, int End, double LBound = 0) const;
	double equivalence_score(const vector<int>& AResult, classifier* BClassifier, int Begin, int End, double LBound = -1) const;
};

}
